package com.hoki.zj.hrm.consumer;

import com.hoki.zj.hrm.domain.KillOrder;
import com.hoki.zj.hrm.domain.KillOrderItem;
import com.hoki.zj.hrm.dto.MyOrderDto;
import com.hoki.zj.hrm.dto.SMSDto;
import com.hoki.zj.hrm.service.IKillOrderItemService;
import com.hoki.zj.hrm.service.IKillOrderService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;

import static com.hoki.zj.hrm.constant.MQMessageConst.*;
import static com.hoki.zj.hrm.domain.KillOrder.*;

@Component
@Slf4j
public class OrderMessageConsumer {

    /** 订单锁,前缀 */
    private static final String PRE_NAME_ORDER_LOCK = "ORDER_LOCK";
    /** 延迟锁 */
    private static final String PRE_NAME_ORDER_DELAY_LOCK = "ORDER_DELAY_LOCK";

    private final IKillOrderService killOrderService;
    private final IKillOrderItemService killOrderItemService;
    private final RedisTemplate<Object,Object> redisTemplate;
    private final RedissonClient redissonClient;
    private final RabbitTemplate rabbitTemplate;

    @Autowired
    public OrderMessageConsumer(IKillOrderService killOrderService,
                                IKillOrderItemService killOrderItemService,
                                RedisTemplate<Object, Object> redisTemplate,
                                RedissonClient redissonClient,
                                RabbitTemplate rabbitTemplate) {
        this.killOrderService = killOrderService;
        this.killOrderItemService = killOrderItemService;
        this.redisTemplate = redisTemplate;
        this.redissonClient = redissonClient;
        this.rabbitTemplate = rabbitTemplate;
    }

    /**
     * 1.消费异步下单消息
     * @param myOrderDto myOrderDto
     * @param channel 通道
     * @param message 消息内容
     *
     */
    @RabbitListener(queues = QUEUE_NAME_ORDER, containerFactory = "rabbitListenerContainerFactory")
    public void receiveOrderMSG(@Payload MyOrderDto myOrderDto, Message message, Channel channel) throws Exception {
        log.info("收到下单消息 {} -> ", myOrderDto);
        KillOrder killOrder = myOrderDto.getKillOrder();
        KillOrderItem killOrderItem = myOrderDto.getKillOrderItem();
        // 1.分布式锁,保证线程安全
        RLock lock = redissonClient.getLock(PRE_NAME_ORDER_LOCK + killOrder.getOrderNo());
        lock.lock();
        Date now = new Date();
        try {
            // 2.幂等处理,查询是否已经创建过订单了
            KillOrder orderInDB = killOrderService.selectByOrderNo(killOrder.getOrderNo());
            if (orderInDB == null) {
                // 3.保存订单
                setKillOrder(killOrder, now);
                killOrderService.insert(killOrder);
                // 4.保存详情
                setKillOrderItem(killOrder, killOrderItem, now);
                killOrderItemService.insert(killOrderItem);
                // 5.发送消息到延迟队列,以便处理支付过期
                rabbitTemplate.convertAndSend(EXCHANGE_NAME_DEAD,"order.delay",myOrderDto);
                // 6.保存订单到Redis用作支付
                redisTemplate.opsForValue().set("order:" + killOrder.getOrderNo(), killOrder);
            }
        } finally {
            if (lock.isLocked()) lock.unlock(); // 最后释放锁
        }
        long deliveryTag = message.getMessageProperties().getDeliveryTag(); // 获取标签
        channel.basicAck(deliveryTag, false); // 手动签收
        channel.close(); // 关闭通道
    }

    private void setKillOrderItem(KillOrder killOrder, KillOrderItem killOrderItem, Date date) {
        killOrderItem.setKillOrderId(killOrder.getId());
        killOrderItem.setPrice(killOrder.getTotalPrice());
        killOrderItem.setCount(killOrder.getKillCount());
        killOrderItem.setCreateTime(date);
    }

    private void setKillOrder(KillOrder killOrder, Date date) {
        killOrder.setCreateTime(date); // 创建时间
        killOrder.setStatusOrder(ORDER_STATUS_WAIT_PAY); // 订单状态
    }

    /**
     * 2.消费过期订单消息
     */
    @RabbitListener(queues = QUEUE_NAME_DEAD, containerFactory = "rabbitListenerContainerFactory")
    public void receiveDelayMSG(@Payload MyOrderDto myOrderDto, Message message, Channel channel) throws Exception {
        log.info("消费过期消息 -> {}", myOrderDto);
        KillOrder killOrder = myOrderDto.getKillOrder();
        KillOrderItem killOrderItem = myOrderDto.getKillOrderItem();
        Long killCourseId = killOrderItem.getKillCourseId(); // 获取courseId
        // 1.分布式锁,保证线程安全
        RLock lock = redissonClient.getLock(PRE_NAME_ORDER_DELAY_LOCK + killOrder.getOrderNo());
        lock.lock();
        try {
            // 获取订单
            KillOrder orderInDB = killOrderService.selectByOrderNo(killOrder.getOrderNo());
            if (orderInDB != null && ORDER_STATUS_WAIT_PAY.equals(orderInDB.getStatusOrder())) {
                // 1.未支付修改订单状态为过期未支付
                orderInDB.setStatusOrder(ORDER_STATUS_PAY_FAILURE);
                System.out.println("id = " + orderInDB.getId());
                killOrderService.updateByKillOrderId(orderInDB);
                // 2.退库存
                RSemaphore semaphore = redissonClient.getSemaphore("KILL_COURSE_STOCK:" + killCourseId.toString());
                semaphore.addPermits(1);
                // 3.删除Redis中的秒杀记录
                redisTemplate.delete("KILL_LOG:" + orderInDB.getUserId());
            }
        } finally {
            if (lock.isLocked()) lock.unlock(); // 最后解锁
        }
        long deliveryTag = message.getMessageProperties().getDeliveryTag(); // 获取标签
        channel.basicAck(deliveryTag, false); // 手动签收
        channel.close(); // 关闭通道
    }

}
